package game.component;

import engine.input.Keys;
import math.Maths;
import math.vector.Vecmath;
import math.vector.vec3f;

public class Motion 
{
    
    private vec3f dirMoveFw; // Motion vectors, not unit vectors
    private vec3f dirMoveRt;
    private vec3f dirMoveFwRt;
    private vec3f dirMoveFwLf;
    
    private float kSpeed;
    private float kDistance;
    private float kDistanceDiag;
    
    public Motion() 
    {
        dirMoveFw = new vec3f();
        dirMoveRt = new vec3f();
        dirMoveFwRt = new vec3f();
        dirMoveFwLf = new vec3f();
    }
    
    public void bindSpeed(float speed) 
    {
        kSpeed = speed;
    }
    
    public void update(Keys keys, Position pos, Rotation rot, float timeCycle) 
    {
        kDistance = timeCycle * kSpeed;
        kDistanceDiag = Maths.SQRT_2_OVER_2 * kDistance;
        
        dirMoveFw.x = rot.sinRots().y; // Motion vectors
        dirMoveFw.z = -rot.cosRots().y;
        dirMoveFw.scalarMult(kDistance);
        
        dirMoveRt.x = rot.cosRots().y;
        dirMoveRt.z = rot.sinRots().y;
        dirMoveRt.scalarMult(kDistance);
        
        dirMoveFwRt.x = rot.sinRots().y + rot.cosRots().y;
        dirMoveFwRt.z = rot.sinRots().y - rot.cosRots().y;
        dirMoveFwRt.scalarMult(kDistanceDiag);
        
        dirMoveFwLf.x = rot.sinRots().y - rot.cosRots().y;
        dirMoveFwLf.z = -(rot.sinRots().y + rot.cosRots().y);
        dirMoveFwLf.scalarMult(kDistanceDiag);
        
        boolean w = keys.isDown(Keys.W);
        boolean s = keys.isDown(Keys.S);
        boolean d = keys.isDown(Keys.D);
        boolean a = keys.isDown(Keys.A);
        boolean r = keys.isDown(Keys.R);
        boolean f = keys.isDown(Keys.F);
        pos.updateAdd(0.0f, r ? kDistance : 0.0f, 0.0f);
        pos.updateSub(0.0f, f ? kDistance : 0.0f, 0.0f);
        int motionDir = this.getMotionDir(w, s, d, a);
        this.moveInDirection(pos, motionDir);
    }
    
    public void reset() 
    {
        dirMoveFw.setTo(Vecmath.ORIGIN);
        dirMoveRt.setTo(Vecmath.ORIGIN);
        dirMoveFwRt.setTo(Vecmath.ORIGIN);
        dirMoveFwLf.setTo(Vecmath.ORIGIN);
    }
    
    
    
    private final int MOT_NONE = 0;
    private final int MOT_FORW = 1;
    private final int MOT_FORW_LEFT = 2;
    private final int MOT_LEFT = 3;
    private final int MOT_BACK_LEFT = 4;
    private final int MOT_BACK = 5;
    private final int MOT_BACK_RGHT = 6;
    private final int MOT_RGHT = 7;
    private final int MOT_FORW_RGHT = 8;
    
    private void moveInDirection(Position pos, int motionDir) 
    {
        switch (motionDir) 
        {
            case (MOT_NONE): 
            {
                break;
            } 
            case (MOT_FORW): 
            {
                pos.updateAdd(dirMoveFw);
                break;
            } 
            case (MOT_FORW_LEFT): 
            {
                pos.updateAdd(dirMoveFwLf);
                break;
            } 
            case (MOT_LEFT): 
            {
                pos.updateSub(dirMoveRt);
                break;
            } 
            case (MOT_BACK_LEFT): 
            {
                pos.updateSub(dirMoveFwRt);
                break;
            } 
            case (MOT_BACK): 
            {
                pos.updateSub(dirMoveFw);
                break;
            } 
            case (MOT_BACK_RGHT): 
            {
                pos.updateSub(dirMoveFwLf);
                break;
            } 
            case (MOT_RGHT): 
            {
                pos.updateAdd(dirMoveRt);
                break;
            } 
            case (MOT_FORW_RGHT): 
            {
                pos.updateAdd(dirMoveFwRt);
                break;
            } 
            default: 
            {
                break;
            }
        }
    }
    
    private int getMotionDir(boolean w, boolean s, boolean d, boolean a) 
    {
        int motionDir = MOT_NONE;
        if (!w || !s || !d || !a) 
        {
            if (w && s) 
            {
                if (d) 
                {
                    motionDir = MOT_RGHT;
                } 
                else if (a) 
                {
                    motionDir = MOT_LEFT;
                }
            } 
            else if (d && a) 
            {
                if (w) 
                {
                    motionDir = MOT_FORW;
                } 
                else if (s) 
                {
                    motionDir = MOT_BACK;
                }
            } 
            else if (w && d) 
            {
                motionDir = MOT_FORW_RGHT;
            } 
            else if (s && d) 
            {
                motionDir = MOT_BACK_RGHT;
            } 
            else if (s && a) 
            {
                motionDir = MOT_BACK_LEFT;
            } 
            else if (w && a) 
            {
                motionDir = MOT_FORW_LEFT;
            } 
            else if (w) 
            {
                motionDir = MOT_FORW;
            } 
            else if (s) 
            {
                motionDir = MOT_BACK;
            } 
            else if (d) 
            {
                motionDir = MOT_RGHT;
            } 
            else if (a) 
            {
                motionDir = MOT_LEFT;
            }
        }
        return motionDir;
    }
    
    public String toString() 
    {
        String s = "";
        s += "MOTION COMPONENT";
        s += "\n   kSpeed: " + kSpeed;
        s += "\n   dirMoveFw: " + dirMoveFw;
        s += "\n   dirMoveRt: " + dirMoveRt;
        s += "\n   dirMoveFwRt: " + dirMoveFwRt;
        s += "\n   dirMoveFwLf: " + dirMoveFwLf;
        return s;
    }
    
}